<file>misc/util.js</file>
<file>misc/weather.js</file>
- <file>perf/basic.js</file>
- <file>perf/closeWithActiveWindows.js</file>
- <file>perf/core.js</file>
- <file>perf/headlessStart.js</file>
- <file>perf/hwtest.js</file>
-
<file>ui/accessDialog.js</file>
<file>ui/altTab.js</file>
<file>ui/animation.js</file>
+++ /dev/null
-// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
-/* eslint camelcase: ["error", { properties: "never", allow: ["^script_"] }] */
-
-const St = imports.gi.St;
-
-const Main = imports.ui.main;
-const MessageTray = imports.ui.messageTray;
-const Scripting = imports.ui.scripting;
-
-// This script tests the most important (basic) functionality of the shell.
-
-export var METRICS = {};
-
-export async function run() {
- console.debug('Running basic perf test');
-
- /* eslint-disable no-await-in-loop */
- Scripting.defineScriptEvent('topBarNavStart', 'Starting to navigate the top bar');
- Scripting.defineScriptEvent('topBarNavDone', 'Done navigating the top bar');
- Scripting.defineScriptEvent('notificationShowStart', 'Showing a notification');
- Scripting.defineScriptEvent('notificationShowDone', 'Done showing a notification');
- Scripting.defineScriptEvent('notificationCloseStart', 'Closing a notification');
- Scripting.defineScriptEvent('notificationCloseDone', 'Done closing a notification');
- Scripting.defineScriptEvent('overviewShowStart', 'Starting to show the overview');
- Scripting.defineScriptEvent('overviewShowDone', 'Overview finished showing');
- Scripting.defineScriptEvent('applicationsShowStart', 'Starting to switch to applications view');
- Scripting.defineScriptEvent('applicationsShowDone', 'Done switching to applications view');
-
- Main.overview.connect('shown',
- () => Scripting.scriptEvent('overviewShowDone'));
-
- await Scripting.sleep(1000);
-
- // navigate through top bar
-
- console.debug('Navigate through top bar');
- Scripting.scriptEvent('topBarNavStart');
- Main.panel.statusArea.quickSettings.menu.open();
- await Scripting.sleep(400);
-
- const { menuManager } = Main.panel;
- while (menuManager.activeMenu &&
- Main.panel.navigate_focus(menuManager.activeMenu.sourceActor,
- St.DirectionType.TAB_BACKWARD, false))
- await Scripting.sleep(400);
- Scripting.scriptEvent('topBarNavDone');
-
- await Scripting.sleep(1000);
-
- // notification
- console.debug('Show notification message');
- const source = new MessageTray.SystemNotificationSource();
- Main.messageTray.add(source);
-
- Scripting.scriptEvent('notificationShowStart');
- source.connect('notification-show',
- () => Scripting.scriptEvent('notificationShowDone'));
-
- const notification = new MessageTray.Notification(source,
- 'A test notification');
- source.showNotification(notification);
- await Scripting.sleep(400);
-
- console.debug('Show date menu');
- Main.panel.statusArea.dateMenu.menu.open();
- await Scripting.sleep(400);
-
- Scripting.scriptEvent('notificationCloseStart');
- notification.connect('destroy',
- () => Scripting.scriptEvent('notificationCloseDone'));
-
- console.debug('Destroy notification message');
- notification.destroy();
- await Scripting.sleep(400);
-
- console.debug('Close date menu');
- Main.panel.statusArea.dateMenu.menu.close();
- await Scripting.waitLeisure();
-
- await Scripting.sleep(1000);
-
- // overview (window picker)
- Scripting.scriptEvent('overviewShowStart');
- Main.overview.show();
- await Scripting.waitLeisure();
- Main.overview.hide();
- await Scripting.waitLeisure();
-
- await Scripting.sleep(1000);
-
- // overview (app picker)
- console.debug('Showing overview');
- Main.overview.show();
- await Scripting.waitLeisure();
-
- Scripting.scriptEvent('applicationsShowStart');
- console.debug('Showing applications');
- // eslint-disable-next-line require-atomic-updates
- Main.overview.dash.showAppsButton.checked = true;
- await Scripting.waitLeisure();
- Scripting.scriptEvent('applicationsShowDone');
- console.debug('Hiding applications');
- // eslint-disable-next-line require-atomic-updates
- Main.overview.dash.showAppsButton.checked = false;
- await Scripting.waitLeisure();
-
- console.debug('Hiding overview');
- Main.overview.hide();
- await Scripting.waitLeisure();
- /* eslint-enable no-await-in-loop */
-
- console.debug('Finished basic perf test');
-}
-
-let topBarNav = false;
-let notificationShown = false;
-let notificationClosed = false;
-let windowPickerShown = false;
-let appPickerShown = false;
-
-export function script_topBarNavDone() {
- topBarNav = true;
-}
-
-export function script_notificationShowDone() {
- notificationShown = true;
-}
-
-export function script_notificationCloseDone() {
- notificationClosed = true;
-}
-
-export function script_overviewShowDone() {
- windowPickerShown = true;
-}
-
-export function script_applicationsShowDone() {
- appPickerShown = true;
-}
-
-export function finish() {
- if (!topBarNav)
- throw new Error('Failed to navigate top bar');
-
- if (!notificationShown)
- throw new Error('Failed to show notification');
-
- if (!notificationClosed)
- throw new Error('Failed to close notification');
-
- if (!windowPickerShown)
- throw new Error('Failed to show window picker');
-
- if (!appPickerShown)
- throw new Error('Failed to show app picker');
-}
+++ /dev/null
-// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
-/* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^malloc", "^glx", "^clutter"] }] */
-
-const Clutter = imports.gi.Clutter;
-
-const Main = imports.ui.main;
-const Scripting = imports.ui.scripting;
-
-/** Run test. */
-export async function run() {
- /* eslint-disable no-await-in-loop */
-
- /* Make created windows remain visible during exit. */
- await Scripting.disableHelperAutoExit();
-
- const seat = Clutter.get_default_backend().get_default_seat();
- const virtualDevice_ =
- seat.create_virtual_device(Clutter.InputDeviceType.KEYBOARD_DEVICE);
-
- Main.overview.hide();
- await Scripting.waitLeisure();
- await Scripting.sleep(1000);
-
- await Scripting.createTestWindow({
- width: 640,
- height: 480,
- textInput: true,
- });
-
- await Scripting.waitTestWindows();
- await Scripting.waitLeisure();
- await Scripting.sleep(1000);
-
- /* eslint-enable no-await-in-loop */
-}
+++ /dev/null
-// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
-/* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^malloc", "^glx", "^clutter"] }] */
-
-const System = imports.system;
-
-const Main = imports.ui.main;
-const Scripting = imports.ui.scripting;
-
-// This performance script measure the most important (core) performance
-// metrics for the shell. By looking at the output metrics of this script
-// someone should be able to get an idea of how well the shell is performing
-// on a particular system.
-
-export var METRICS = {
- overviewLatencyFirst: {
- description: 'Time to first frame after triggering overview, first time',
- units: 'us',
- },
- overviewFpsFirst: {
- description: 'Frame rate when going to the overview, first time',
- units: 'frames / s',
- },
- overviewLatencySubsequent: {
- description: 'Time to first frame after triggering overview, second time',
- units: 'us',
- },
- overviewFpsSubsequent: {
- description: 'Frames rate when going to the overview, second time',
- units: 'frames / s',
- },
- overviewFps5Windows: {
- description: 'Frames rate when going to the overview, 5 windows open',
- units: 'frames / s',
- },
- overviewFps10Windows: {
- description: 'Frames rate when going to the overview, 10 windows open',
- units: 'frames / s',
- },
- overviewFps5Maximized: {
- description: 'Frames rate when going to the overview, 5 maximized windows open',
- units: 'frames / s',
- },
- overviewFps10Maximized: {
- description: 'Frames rate when going to the overview, 10 maximized windows open',
- units: 'frames / s',
- },
- overviewFps5Alpha: {
- description: 'Frames rate when going to the overview, 5 alpha-transparent windows open',
- units: 'frames / s',
- },
- overviewFps10Alpha: {
- description: 'Frames rate when going to the overview, 10 alpha-transparent windows open',
- units: 'frames / s',
- },
- usedAfterOverview: {
- description: "Malloc'ed bytes after the overview is shown once",
- units: 'B',
- },
- leakedAfterOverview: {
- description: "Additional malloc'ed bytes the second time the overview is shown",
- units: 'B',
- },
- applicationsShowTimeFirst: {
- description: 'Time to switch to applications view, first time',
- units: 'us',
- },
- applicationsShowTimeSubsequent: {
- description: 'Time to switch to applications view, second time',
- units: 'us',
- },
-};
-
-const WINDOW_CONFIGS = [{
- width: 640, height: 480,
- alpha: false, maximized: false, count: 1, metric: 'overviewFpsSubsequent',
-}, {
- width: 640, height: 480,
- alpha: false, maximized: false, count: 5, metric: 'overviewFps5Windows',
-}, {
- width: 640, height: 480,
- alpha: false, maximized: false, count: 10, metric: 'overviewFps10Windows',
-}, {
- width: 640, height: 480,
- alpha: false, maximized: true, count: 5, metric: 'overviewFps5Maximized',
-}, {
- width: 640, height: 480,
- alpha: false, maximized: true, count: 10, metric: 'overviewFps10Maximized',
-}, {
- width: 640, height: 480,
- alpha: true, maximized: false, count: 5, metric: 'overviewFps5Alpha',
-}, {
- width: 640, height: 480,
- alpha: true, maximized: false, count: 10, metric: 'overviewFps10Alpha',
-}];
-
-export async function run() {
- /* eslint-disable no-await-in-loop */
- Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview");
- Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing");
- Scripting.defineScriptEvent("afterShowHide", "After a show/hide cycle for the overview");
- Scripting.defineScriptEvent("applicationsShowStart", "Starting to switch to applications view");
- Scripting.defineScriptEvent("applicationsShowDone", "Done switching to applications view");
-
- // Enable recording of timestamps for different points in the frame cycle
- global.frame_timestamps = true;
-
- Main.overview.connect('shown', () => {
- Scripting.scriptEvent('overviewShowDone');
- });
-
- await Scripting.sleep(1000);
-
- for (let i = 0; i < 2 * WINDOW_CONFIGS.length; i++) {
- // We go to the overview twice for each configuration; the first time
- // to calculate the mipmaps for the windows, the second time to get
- // a clean set of numbers.
- if ((i % 2) == 0) {
- let config = WINDOW_CONFIGS[i / 2];
- await Scripting.destroyTestWindows();
-
- for (let k = 0; k < config.count; k++) {
- await Scripting.createTestWindow({
- width: config.width,
- height: config.height,
- alpha: config.alpha,
- maximized: config.maximized,
- });
- }
-
- await Scripting.waitTestWindows();
- await Scripting.sleep(1000);
- await Scripting.waitLeisure();
- }
-
- Scripting.scriptEvent('overviewShowStart');
- Main.overview.show();
-
- await Scripting.waitLeisure();
- Main.overview.hide();
- await Scripting.waitLeisure();
-
- System.gc();
- await Scripting.sleep(1000);
- Scripting.collectStatistics();
- Scripting.scriptEvent('afterShowHide');
- }
-
- await Scripting.destroyTestWindows();
- await Scripting.sleep(1000);
-
- Main.overview.show();
- await Scripting.waitLeisure();
-
- for (let i = 0; i < 2; i++) {
- Scripting.scriptEvent('applicationsShowStart');
- // eslint-disable-next-line require-atomic-updates
- Main.overview.dash.showAppsButton.checked = true;
- await Scripting.waitLeisure();
- Scripting.scriptEvent('applicationsShowDone');
- // eslint-disable-next-line require-atomic-updates
- Main.overview.dash.showAppsButton.checked = false;
- await Scripting.waitLeisure();
- }
- /* eslint-enable no-await-in-loop */
-}
-
-let showingOverview = false;
-let finishedShowingOverview = false;
-let overviewShowStart;
-let overviewFrames;
-let overviewLatency;
-let mallocUsedSize = 0;
-let overviewShowCount = 0;
-let haveSwapComplete = false;
-let applicationsShowStart;
-let applicationsShowCount = 0;
-
-export function script_overviewShowStart(time) {
- showingOverview = true;
- finishedShowingOverview = false;
- overviewShowStart = time;
- overviewFrames = 0;
-}
-
-export function script_overviewShowDone(_time) {
- // We've set up the state at the end of the zoom out, but we
- // need to wait for one more frame to paint before we count
- // ourselves as done.
- finishedShowingOverview = true;
-}
-
-export function script_applicationsShowStart(time) {
- applicationsShowStart = time;
-}
-
-export function script_applicationsShowDone(time) {
- applicationsShowCount++;
- if (applicationsShowCount == 1)
- METRICS.applicationsShowTimeFirst.value = time - applicationsShowStart;
- else
- METRICS.applicationsShowTimeSubsequent.value = time - applicationsShowStart;
-}
-
-export function script_afterShowHide(_time) {
- if (overviewShowCount == 1)
- METRICS.usedAfterOverview.value = mallocUsedSize;
- else
- METRICS.leakedAfterOverview.value = mallocUsedSize - METRICS.usedAfterOverview.value;
-}
-
-export function malloc_usedSize(time, bytes) {
- mallocUsedSize = bytes;
-}
-
-function _frameDone(time) {
- if (showingOverview) {
- if (overviewFrames == 0)
- overviewLatency = time - overviewShowStart;
-
- overviewFrames++;
- }
-
- if (finishedShowingOverview) {
- showingOverview = false;
- finishedShowingOverview = false;
- overviewShowCount++;
-
- let dt = (time - (overviewShowStart + overviewLatency)) / 1000000;
-
- // If we see a start frame and an end frame, that would
- // be 1 frame for a FPS computation, hence the '- 1'
- let fps = (overviewFrames - 1) / dt;
-
- if (overviewShowCount == 1) {
- METRICS.overviewLatencyFirst.value = overviewLatency;
- METRICS.overviewFpsFirst.value = fps;
- } else if (overviewShowCount == 2) {
- METRICS.overviewLatencySubsequent.value = overviewLatency;
- }
-
- // Other than overviewFpsFirst, we collect FPS metrics the second
- // we show each window configuration. overviewShowCount is 1,2,3...
- if (overviewShowCount % 2 == 0) {
- let config = WINDOW_CONFIGS[(overviewShowCount / 2) - 1];
- METRICS[config.metric].value = fps;
- }
- }
-}
-
-export function glx_swapComplete(time, swapTime) {
- haveSwapComplete = true;
-
- _frameDone(swapTime);
-}
-
-export function clutter_stagePaintDone(time) {
- // If we aren't receiving GLXBufferSwapComplete events, then we approximate
- // the time the user sees a frame with the time we finished doing drawing
- // commands for the frame. This doesn't take into account the time for
- // the GPU to finish painting, and the time for waiting for the buffer
- // swap, but if this are uniform - every frame takes the same time to draw -
- // then it won't upset our FPS calculation, though the latency value
- // will be slightly too low.
-
- if (!haveSwapComplete)
- _frameDone(time);
-}
+++ /dev/null
-// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
-/* eslint camelcase: ["error", { properties: "never", allow: ["^script_"] }] */
-
-const GLib = imports.gi.GLib;
-const MetaTest = imports.gi.MetaTest;
-const Shell = imports.gi.Shell;
-
-const Main = imports.ui.main;
-const Scripting = imports.ui.scripting;
-
-// This script tests that the shell handles connecting monitors after startup
-// is properly handled.
-
-export var METRICS = {};
-
-let _testMonitor = null;
-
-/**
- * init:
- */
-export function init() {
- global.connect('shutdown', () => {
- _testMonitor?.destroy();
- });
- GLib.timeout_add_seconds(
- GLib.PRIORITY_LOW, 2,
- () => {
- log('Connecting 1280x720 test monitor');
- _testMonitor = MetaTest.TestMonitor.new(
- global.context, 1280, 720, 60.0);
- });
- Scripting.defineScriptEvent('monitorsChanged', 'Monitors changed');
-
- const display = global.display;
- console.assert(display.get_n_monitors() === 0, 'Not running headless');
-
- const monitorManager = global.backend.get_monitor_manager();
- const monitorsChangedHandlerId = monitorManager.connect('monitors-changed',
- () => {
- console.assert(display.get_n_monitors() === 1,
- 'Expected a single monitor');
- Scripting.scriptEvent('monitorsChanged');
- monitorManager.disconnect(monitorsChangedHandlerId);
- });
- Shell.PerfLog.get_default().set_enabled(true);
-}
-
-/**
- * run:
- */
-export async function run() {
- /* eslint-disable no-await-in-loop */
- Scripting.defineScriptEvent('overviewShowDone', 'Overview finished showing');
- Scripting.defineScriptEvent('overviewHideDone', 'Overview finished hiding');
-
- Main.overview.connect('shown',
- () => Scripting.scriptEvent('overviewShowDone'));
- Main.overview.connect('hidden',
- () => Scripting.scriptEvent('overviewHideDone'));
-
- Main.overview.hide();
- await Scripting.waitLeisure();
-
- Main.overview.show();
- await Scripting.waitLeisure();
-
- /* eslint-enable no-await-in-loop */
-}
-
-let monitorsChanged = false;
-let overviewHidden = false;
-let overviewShown = false;
-
-/**
- * script_monitorsChanged:
- */
-export function script_monitorsChanged() {
- monitorsChanged = true;
-}
-
-/**
- * script_overviewHideDone:
- */
-export function script_overviewHideDone() {
- overviewHidden = true;
-}
-
-/**
- * script_overviewShowDone:
- */
-export function script_overviewShowDone() {
- overviewShown = true;
-}
-
-/**
- * finish:
- */
-export function finish() {
- if (!monitorsChanged)
- throw new Error('Monitors never changed');
-
- if (!overviewHidden)
- throw new Error('Failed to hide overview');
-
- if (!overviewShown)
- throw new Error('Failed to show overview');
-}
+++ /dev/null
-/* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^clutter"] }] */
-const Clutter = imports.gi.Clutter;
-const Gio = imports.gi.Gio;
-const Shell = imports.gi.Shell;
-const Main = imports.ui.main;
-const Scripting = imports.ui.scripting;
-
-export var METRICS = {
- timeToDesktop: {
- description: 'Time from starting graphical.target to desktop showing',
- units: 'us',
- },
-
- overviewShowTime: {
- description: 'Time to switch to overview view, first time',
- units: 'us',
- },
-
- applicationsShowTime: {
- description: 'Time to switch to applications view, first time',
- units: 'us',
- },
-
- mainViewRedrawTime: {
- description: 'Time to redraw the main view, full screen',
- units: 'us',
- },
-
- overviewRedrawTime: {
- description: 'Time to redraw the overview, full screen, 5 windows',
- units: 'us',
- },
-
- applicationRedrawTime: {
- description: 'Time to redraw frame with a maximized application update',
- units: 'us',
- },
-
- geditStartTime: {
- description: 'Time from gedit launch to window drawn',
- units: 'us',
- },
-};
-
-function waitAndDraw(milliseconds) {
- let cb;
-
- let timeline = new Clutter.Timeline({ duration: milliseconds });
- timeline.start();
-
- timeline.connect('new-frame', (_timeline, _frame) => {
- global.stage.queue_redraw();
- });
-
- timeline.connect('completed', () => {
- timeline.stop();
- if (cb)
- cb();
- });
-
- return callback => (cb = callback);
-}
-
-function waitSignal(object, signal) {
- let cb;
-
- let id = object.connect(signal, () => {
- object.disconnect(id);
- if (cb)
- cb();
- });
-
- return callback => (cb = callback);
-}
-
-function extractBootTimestamp() {
- const sp = Gio.Subprocess.new([
- 'journalctl', '-b',
- 'MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5',
- 'UNIT=graphical.target',
- '-o',
- 'json',
- ], Gio.SubprocessFlags.STDOUT_PIPE);
- let result = null;
-
- let datastream = Gio.DataInputStream.new(sp.get_stdout_pipe());
- while (true) { // eslint-disable-line no-constant-condition
- let [line, length_] = datastream.read_line_utf8(null);
- if (line === null)
- break;
-
- let fields = JSON.parse(line);
- result = Number(fields['__MONOTONIC_TIMESTAMP']);
- }
- datastream.close(null);
- return result;
-}
-
-export async function run() {
- /* eslint-disable no-await-in-loop */
- Scripting.defineScriptEvent("desktopShown", "Finished initial animation");
- Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview");
- Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing");
- Scripting.defineScriptEvent("applicationsShowStart", "Starting to switch to applications view");
- Scripting.defineScriptEvent("applicationsShowDone", "Done switching to applications view");
- Scripting.defineScriptEvent("mainViewDrawStart", "Drawing main view");
- Scripting.defineScriptEvent("mainViewDrawDone", "Ending timing main view drawing");
- Scripting.defineScriptEvent("overviewDrawStart", "Drawing overview");
- Scripting.defineScriptEvent("overviewDrawDone", "Ending timing overview drawing");
- Scripting.defineScriptEvent("redrawTestStart", "Drawing application window");
- Scripting.defineScriptEvent("redrawTestDone", "Ending timing application window drawing");
- Scripting.defineScriptEvent("collectTimings", "Accumulate frame timings from redraw tests");
- Scripting.defineScriptEvent("geditLaunch", "gedit application launch");
- Scripting.defineScriptEvent("geditFirstFrame", "first frame of gedit window drawn");
-
- await Scripting.waitLeisure();
- Scripting.scriptEvent('desktopShown');
-
- let interfaceSettings = new Gio.Settings({
- schema_id: 'org.gnome.desktop.interface',
- });
- interfaceSettings.set_boolean('enable-animations', false);
-
- Scripting.scriptEvent('overviewShowStart');
- Main.overview.show();
- await Scripting.waitLeisure();
- Scripting.scriptEvent('overviewShowDone');
-
- await Scripting.sleep(1000);
-
- Scripting.scriptEvent('applicationsShowStart');
- // eslint-disable-next-line require-atomic-updates
- Main.overview.dash.showAppsButton.checked = true;
-
- await Scripting.waitLeisure();
- Scripting.scriptEvent('applicationsShowDone');
-
- await Scripting.sleep(1000);
-
- Main.overview.hide();
- await Scripting.waitLeisure();
-
- // --------------------- //
- // Tests of redraw speed //
- // --------------------- //
-
- global.frame_timestamps = true;
- global.frame_finish_timestamp = true;
-
- for (let k = 0; k < 5; k++)
- await Scripting.createTestWindow({ maximized: true });
- await Scripting.waitTestWindows();
-
- await Scripting.sleep(1000);
-
- Scripting.scriptEvent('mainViewDrawStart');
- await waitAndDraw(1000);
- Scripting.scriptEvent('mainViewDrawDone');
-
- Main.overview.show();
- Scripting.waitLeisure();
-
- await Scripting.sleep(1500);
-
- Scripting.scriptEvent('overviewDrawStart');
- await waitAndDraw(1000);
- Scripting.scriptEvent('overviewDrawDone');
-
- await Scripting.destroyTestWindows();
- Main.overview.hide();
-
- await Scripting.createTestWindow({
- maximized: true,
- redraws: true,
- });
- await Scripting.waitTestWindows();
-
- await Scripting.sleep(1000);
-
- Scripting.scriptEvent('redrawTestStart');
- await Scripting.sleep(1000);
- Scripting.scriptEvent('redrawTestDone');
-
- await Scripting.sleep(1000);
- Scripting.scriptEvent('collectTimings');
-
- await Scripting.destroyTestWindows();
-
- global.frame_timestamps = false;
- global.frame_finish_timestamp = false;
-
- await Scripting.sleep(1000);
-
- let appSys = Shell.AppSystem.get_default();
- let app = appSys.lookup_app('org.gnome.gedit.desktop');
-
- Scripting.scriptEvent('geditLaunch');
- app.activate();
-
- let windows = app.get_windows();
- if (windows.length > 0)
- throw new Error('gedit was already running');
-
- while (windows.length == 0) {
- await waitSignal(global.display, 'window-created');
- windows = app.get_windows();
- }
-
- let actor = windows[0].get_compositor_private();
- await waitSignal(actor, 'first-frame');
- Scripting.scriptEvent('geditFirstFrame');
-
- await Scripting.sleep(1000);
-
- windows[0].delete(global.get_current_time());
-
- await Scripting.sleep(1000);
-
- interfaceSettings.set_boolean('enable-animations', true);
- /* eslint-enable no-await-in-loop */
-}
-
-let overviewShowStart;
-let applicationsShowStart;
-let stagePaintStart;
-let redrawTiming;
-let redrawTimes = {};
-let geditLaunchTime;
-
-export function script_desktopShown(time) {
- let bootTimestamp = extractBootTimestamp();
- METRICS.timeToDesktop.value = time - bootTimestamp;
-}
-
-export function script_overviewShowStart(time) {
- overviewShowStart = time;
-}
-
-export function script_overviewShowDone(time) {
- METRICS.overviewShowTime.value = time - overviewShowStart;
-}
-
-export function script_applicationsShowStart(time) {
- applicationsShowStart = time;
-}
-
-export function script_applicationsShowDone(time) {
- METRICS.applicationsShowTime.value = time - applicationsShowStart;
-}
-
-export function script_mainViewDrawStart(_time) {
- redrawTiming = 'mainView';
-}
-
-export function script_mainViewDrawDone(_time) {
- redrawTiming = null;
-}
-
-export function script_overviewDrawStart(_time) {
- redrawTiming = 'overview';
-}
-
-export function script_overviewDrawDone(_time) {
- redrawTiming = null;
-}
-
-export function script_redrawTestStart(_time) {
- redrawTiming = 'application';
-}
-
-export function script_redrawTestDone(_time) {
- redrawTiming = null;
-}
-
-export function script_collectTimings(_time) {
- for (let timing in redrawTimes) {
- let times = redrawTimes[timing];
- times.sort((a, b) => a - b);
-
- let len = times.length;
- let median;
-
- if (len == 0)
- median = -1;
- else if (len % 2 == 1)
- median = times[(len - 1) / 2];
- else
- median = Math.round((times[len / 2 - 1] + times[len / 2]) / 2);
-
- METRICS[`${timing}RedrawTime`].value = median;
- }
-}
-
-export function script_geditLaunch(time) {
- geditLaunchTime = time;
-}
-
-export function script_geditFirstFrame(time) {
- METRICS.geditStartTime.value = time - geditLaunchTime;
-}
-
-export function clutter_stagePaintStart(time) {
- stagePaintStart = time;
-}
-
-export function clutter_paintCompletedTimestamp(time) {
- if (redrawTiming != null && stagePaintStart != null) {
- if (!(redrawTiming in redrawTimes))
- redrawTimes[redrawTiming] = [];
- redrawTimes[redrawTiming].push(time - stagePaintStart);
- }
- stagePaintStart = null;
-}
test_tool,
'--headless',
options,
- '@0@/js/perf/@1@.js'.format(meson.project_source_root(), test_name),
+ '@0@/shell/@1@.js'.format(meson.current_source_dir(), test_name),
],
is_parallel: false,
env: shell_testenv,
--- /dev/null
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+/* eslint camelcase: ["error", { properties: "never", allow: ["^script_"] }] */
+
+const St = imports.gi.St;
+
+const Main = imports.ui.main;
+const MessageTray = imports.ui.messageTray;
+const Scripting = imports.ui.scripting;
+
+// This script tests the most important (basic) functionality of the shell.
+
+export var METRICS = {};
+
+export async function run() {
+ console.debug('Running basic perf test');
+
+ /* eslint-disable no-await-in-loop */
+ Scripting.defineScriptEvent('topBarNavStart', 'Starting to navigate the top bar');
+ Scripting.defineScriptEvent('topBarNavDone', 'Done navigating the top bar');
+ Scripting.defineScriptEvent('notificationShowStart', 'Showing a notification');
+ Scripting.defineScriptEvent('notificationShowDone', 'Done showing a notification');
+ Scripting.defineScriptEvent('notificationCloseStart', 'Closing a notification');
+ Scripting.defineScriptEvent('notificationCloseDone', 'Done closing a notification');
+ Scripting.defineScriptEvent('overviewShowStart', 'Starting to show the overview');
+ Scripting.defineScriptEvent('overviewShowDone', 'Overview finished showing');
+ Scripting.defineScriptEvent('applicationsShowStart', 'Starting to switch to applications view');
+ Scripting.defineScriptEvent('applicationsShowDone', 'Done switching to applications view');
+
+ Main.overview.connect('shown',
+ () => Scripting.scriptEvent('overviewShowDone'));
+
+ await Scripting.sleep(1000);
+
+ // navigate through top bar
+
+ console.debug('Navigate through top bar');
+ Scripting.scriptEvent('topBarNavStart');
+ Main.panel.statusArea.quickSettings.menu.open();
+ await Scripting.sleep(400);
+
+ const { menuManager } = Main.panel;
+ while (menuManager.activeMenu &&
+ Main.panel.navigate_focus(menuManager.activeMenu.sourceActor,
+ St.DirectionType.TAB_BACKWARD, false))
+ await Scripting.sleep(400);
+ Scripting.scriptEvent('topBarNavDone');
+
+ await Scripting.sleep(1000);
+
+ // notification
+ console.debug('Show notification message');
+ const source = new MessageTray.SystemNotificationSource();
+ Main.messageTray.add(source);
+
+ Scripting.scriptEvent('notificationShowStart');
+ source.connect('notification-show',
+ () => Scripting.scriptEvent('notificationShowDone'));
+
+ const notification = new MessageTray.Notification(source,
+ 'A test notification');
+ source.showNotification(notification);
+ await Scripting.sleep(400);
+
+ console.debug('Show date menu');
+ Main.panel.statusArea.dateMenu.menu.open();
+ await Scripting.sleep(400);
+
+ Scripting.scriptEvent('notificationCloseStart');
+ notification.connect('destroy',
+ () => Scripting.scriptEvent('notificationCloseDone'));
+
+ console.debug('Destroy notification message');
+ notification.destroy();
+ await Scripting.sleep(400);
+
+ console.debug('Close date menu');
+ Main.panel.statusArea.dateMenu.menu.close();
+ await Scripting.waitLeisure();
+
+ await Scripting.sleep(1000);
+
+ // overview (window picker)
+ Scripting.scriptEvent('overviewShowStart');
+ Main.overview.show();
+ await Scripting.waitLeisure();
+ Main.overview.hide();
+ await Scripting.waitLeisure();
+
+ await Scripting.sleep(1000);
+
+ // overview (app picker)
+ console.debug('Showing overview');
+ Main.overview.show();
+ await Scripting.waitLeisure();
+
+ Scripting.scriptEvent('applicationsShowStart');
+ console.debug('Showing applications');
+ // eslint-disable-next-line require-atomic-updates
+ Main.overview.dash.showAppsButton.checked = true;
+ await Scripting.waitLeisure();
+ Scripting.scriptEvent('applicationsShowDone');
+ console.debug('Hiding applications');
+ // eslint-disable-next-line require-atomic-updates
+ Main.overview.dash.showAppsButton.checked = false;
+ await Scripting.waitLeisure();
+
+ console.debug('Hiding overview');
+ Main.overview.hide();
+ await Scripting.waitLeisure();
+ /* eslint-enable no-await-in-loop */
+
+ console.debug('Finished basic perf test');
+}
+
+let topBarNav = false;
+let notificationShown = false;
+let notificationClosed = false;
+let windowPickerShown = false;
+let appPickerShown = false;
+
+export function script_topBarNavDone() {
+ topBarNav = true;
+}
+
+export function script_notificationShowDone() {
+ notificationShown = true;
+}
+
+export function script_notificationCloseDone() {
+ notificationClosed = true;
+}
+
+export function script_overviewShowDone() {
+ windowPickerShown = true;
+}
+
+export function script_applicationsShowDone() {
+ appPickerShown = true;
+}
+
+export function finish() {
+ if (!topBarNav)
+ throw new Error('Failed to navigate top bar');
+
+ if (!notificationShown)
+ throw new Error('Failed to show notification');
+
+ if (!notificationClosed)
+ throw new Error('Failed to close notification');
+
+ if (!windowPickerShown)
+ throw new Error('Failed to show window picker');
+
+ if (!appPickerShown)
+ throw new Error('Failed to show app picker');
+}
--- /dev/null
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+/* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^malloc", "^glx", "^clutter"] }] */
+
+const Clutter = imports.gi.Clutter;
+
+const Main = imports.ui.main;
+const Scripting = imports.ui.scripting;
+
+/** Run test. */
+export async function run() {
+ /* eslint-disable no-await-in-loop */
+
+ /* Make created windows remain visible during exit. */
+ await Scripting.disableHelperAutoExit();
+
+ const seat = Clutter.get_default_backend().get_default_seat();
+ const virtualDevice_ =
+ seat.create_virtual_device(Clutter.InputDeviceType.KEYBOARD_DEVICE);
+
+ Main.overview.hide();
+ await Scripting.waitLeisure();
+ await Scripting.sleep(1000);
+
+ await Scripting.createTestWindow({
+ width: 640,
+ height: 480,
+ textInput: true,
+ });
+
+ await Scripting.waitTestWindows();
+ await Scripting.waitLeisure();
+ await Scripting.sleep(1000);
+
+ /* eslint-enable no-await-in-loop */
+}
--- /dev/null
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+/* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^malloc", "^glx", "^clutter"] }] */
+
+const System = imports.system;
+
+const Main = imports.ui.main;
+const Scripting = imports.ui.scripting;
+
+// This performance script measure the most important (core) performance
+// metrics for the shell. By looking at the output metrics of this script
+// someone should be able to get an idea of how well the shell is performing
+// on a particular system.
+
+export var METRICS = {
+ overviewLatencyFirst: {
+ description: 'Time to first frame after triggering overview, first time',
+ units: 'us',
+ },
+ overviewFpsFirst: {
+ description: 'Frame rate when going to the overview, first time',
+ units: 'frames / s',
+ },
+ overviewLatencySubsequent: {
+ description: 'Time to first frame after triggering overview, second time',
+ units: 'us',
+ },
+ overviewFpsSubsequent: {
+ description: 'Frames rate when going to the overview, second time',
+ units: 'frames / s',
+ },
+ overviewFps5Windows: {
+ description: 'Frames rate when going to the overview, 5 windows open',
+ units: 'frames / s',
+ },
+ overviewFps10Windows: {
+ description: 'Frames rate when going to the overview, 10 windows open',
+ units: 'frames / s',
+ },
+ overviewFps5Maximized: {
+ description: 'Frames rate when going to the overview, 5 maximized windows open',
+ units: 'frames / s',
+ },
+ overviewFps10Maximized: {
+ description: 'Frames rate when going to the overview, 10 maximized windows open',
+ units: 'frames / s',
+ },
+ overviewFps5Alpha: {
+ description: 'Frames rate when going to the overview, 5 alpha-transparent windows open',
+ units: 'frames / s',
+ },
+ overviewFps10Alpha: {
+ description: 'Frames rate when going to the overview, 10 alpha-transparent windows open',
+ units: 'frames / s',
+ },
+ usedAfterOverview: {
+ description: "Malloc'ed bytes after the overview is shown once",
+ units: 'B',
+ },
+ leakedAfterOverview: {
+ description: "Additional malloc'ed bytes the second time the overview is shown",
+ units: 'B',
+ },
+ applicationsShowTimeFirst: {
+ description: 'Time to switch to applications view, first time',
+ units: 'us',
+ },
+ applicationsShowTimeSubsequent: {
+ description: 'Time to switch to applications view, second time',
+ units: 'us',
+ },
+};
+
+const WINDOW_CONFIGS = [{
+ width: 640, height: 480,
+ alpha: false, maximized: false, count: 1, metric: 'overviewFpsSubsequent',
+}, {
+ width: 640, height: 480,
+ alpha: false, maximized: false, count: 5, metric: 'overviewFps5Windows',
+}, {
+ width: 640, height: 480,
+ alpha: false, maximized: false, count: 10, metric: 'overviewFps10Windows',
+}, {
+ width: 640, height: 480,
+ alpha: false, maximized: true, count: 5, metric: 'overviewFps5Maximized',
+}, {
+ width: 640, height: 480,
+ alpha: false, maximized: true, count: 10, metric: 'overviewFps10Maximized',
+}, {
+ width: 640, height: 480,
+ alpha: true, maximized: false, count: 5, metric: 'overviewFps5Alpha',
+}, {
+ width: 640, height: 480,
+ alpha: true, maximized: false, count: 10, metric: 'overviewFps10Alpha',
+}];
+
+export async function run() {
+ /* eslint-disable no-await-in-loop */
+ Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview");
+ Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing");
+ Scripting.defineScriptEvent("afterShowHide", "After a show/hide cycle for the overview");
+ Scripting.defineScriptEvent("applicationsShowStart", "Starting to switch to applications view");
+ Scripting.defineScriptEvent("applicationsShowDone", "Done switching to applications view");
+
+ // Enable recording of timestamps for different points in the frame cycle
+ global.frame_timestamps = true;
+
+ Main.overview.connect('shown', () => {
+ Scripting.scriptEvent('overviewShowDone');
+ });
+
+ await Scripting.sleep(1000);
+
+ for (let i = 0; i < 2 * WINDOW_CONFIGS.length; i++) {
+ // We go to the overview twice for each configuration; the first time
+ // to calculate the mipmaps for the windows, the second time to get
+ // a clean set of numbers.
+ if ((i % 2) == 0) {
+ let config = WINDOW_CONFIGS[i / 2];
+ await Scripting.destroyTestWindows();
+
+ for (let k = 0; k < config.count; k++) {
+ await Scripting.createTestWindow({
+ width: config.width,
+ height: config.height,
+ alpha: config.alpha,
+ maximized: config.maximized,
+ });
+ }
+
+ await Scripting.waitTestWindows();
+ await Scripting.sleep(1000);
+ await Scripting.waitLeisure();
+ }
+
+ Scripting.scriptEvent('overviewShowStart');
+ Main.overview.show();
+
+ await Scripting.waitLeisure();
+ Main.overview.hide();
+ await Scripting.waitLeisure();
+
+ System.gc();
+ await Scripting.sleep(1000);
+ Scripting.collectStatistics();
+ Scripting.scriptEvent('afterShowHide');
+ }
+
+ await Scripting.destroyTestWindows();
+ await Scripting.sleep(1000);
+
+ Main.overview.show();
+ await Scripting.waitLeisure();
+
+ for (let i = 0; i < 2; i++) {
+ Scripting.scriptEvent('applicationsShowStart');
+ // eslint-disable-next-line require-atomic-updates
+ Main.overview.dash.showAppsButton.checked = true;
+ await Scripting.waitLeisure();
+ Scripting.scriptEvent('applicationsShowDone');
+ // eslint-disable-next-line require-atomic-updates
+ Main.overview.dash.showAppsButton.checked = false;
+ await Scripting.waitLeisure();
+ }
+ /* eslint-enable no-await-in-loop */
+}
+
+let showingOverview = false;
+let finishedShowingOverview = false;
+let overviewShowStart;
+let overviewFrames;
+let overviewLatency;
+let mallocUsedSize = 0;
+let overviewShowCount = 0;
+let haveSwapComplete = false;
+let applicationsShowStart;
+let applicationsShowCount = 0;
+
+export function script_overviewShowStart(time) {
+ showingOverview = true;
+ finishedShowingOverview = false;
+ overviewShowStart = time;
+ overviewFrames = 0;
+}
+
+export function script_overviewShowDone(_time) {
+ // We've set up the state at the end of the zoom out, but we
+ // need to wait for one more frame to paint before we count
+ // ourselves as done.
+ finishedShowingOverview = true;
+}
+
+export function script_applicationsShowStart(time) {
+ applicationsShowStart = time;
+}
+
+export function script_applicationsShowDone(time) {
+ applicationsShowCount++;
+ if (applicationsShowCount == 1)
+ METRICS.applicationsShowTimeFirst.value = time - applicationsShowStart;
+ else
+ METRICS.applicationsShowTimeSubsequent.value = time - applicationsShowStart;
+}
+
+export function script_afterShowHide(_time) {
+ if (overviewShowCount == 1)
+ METRICS.usedAfterOverview.value = mallocUsedSize;
+ else
+ METRICS.leakedAfterOverview.value = mallocUsedSize - METRICS.usedAfterOverview.value;
+}
+
+export function malloc_usedSize(time, bytes) {
+ mallocUsedSize = bytes;
+}
+
+function _frameDone(time) {
+ if (showingOverview) {
+ if (overviewFrames == 0)
+ overviewLatency = time - overviewShowStart;
+
+ overviewFrames++;
+ }
+
+ if (finishedShowingOverview) {
+ showingOverview = false;
+ finishedShowingOverview = false;
+ overviewShowCount++;
+
+ let dt = (time - (overviewShowStart + overviewLatency)) / 1000000;
+
+ // If we see a start frame and an end frame, that would
+ // be 1 frame for a FPS computation, hence the '- 1'
+ let fps = (overviewFrames - 1) / dt;
+
+ if (overviewShowCount == 1) {
+ METRICS.overviewLatencyFirst.value = overviewLatency;
+ METRICS.overviewFpsFirst.value = fps;
+ } else if (overviewShowCount == 2) {
+ METRICS.overviewLatencySubsequent.value = overviewLatency;
+ }
+
+ // Other than overviewFpsFirst, we collect FPS metrics the second
+ // we show each window configuration. overviewShowCount is 1,2,3...
+ if (overviewShowCount % 2 == 0) {
+ let config = WINDOW_CONFIGS[(overviewShowCount / 2) - 1];
+ METRICS[config.metric].value = fps;
+ }
+ }
+}
+
+export function glx_swapComplete(time, swapTime) {
+ haveSwapComplete = true;
+
+ _frameDone(swapTime);
+}
+
+export function clutter_stagePaintDone(time) {
+ // If we aren't receiving GLXBufferSwapComplete events, then we approximate
+ // the time the user sees a frame with the time we finished doing drawing
+ // commands for the frame. This doesn't take into account the time for
+ // the GPU to finish painting, and the time for waiting for the buffer
+ // swap, but if this are uniform - every frame takes the same time to draw -
+ // then it won't upset our FPS calculation, though the latency value
+ // will be slightly too low.
+
+ if (!haveSwapComplete)
+ _frameDone(time);
+}
--- /dev/null
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+/* eslint camelcase: ["error", { properties: "never", allow: ["^script_"] }] */
+
+const GLib = imports.gi.GLib;
+const MetaTest = imports.gi.MetaTest;
+const Shell = imports.gi.Shell;
+
+const Main = imports.ui.main;
+const Scripting = imports.ui.scripting;
+
+// This script tests that the shell handles connecting monitors after startup
+// is properly handled.
+
+export var METRICS = {};
+
+let _testMonitor = null;
+
+/**
+ * init:
+ */
+export function init() {
+ global.connect('shutdown', () => {
+ _testMonitor?.destroy();
+ });
+ GLib.timeout_add_seconds(
+ GLib.PRIORITY_LOW, 2,
+ () => {
+ log('Connecting 1280x720 test monitor');
+ _testMonitor = MetaTest.TestMonitor.new(
+ global.context, 1280, 720, 60.0);
+ });
+ Scripting.defineScriptEvent('monitorsChanged', 'Monitors changed');
+
+ const display = global.display;
+ console.assert(display.get_n_monitors() === 0, 'Not running headless');
+
+ const monitorManager = global.backend.get_monitor_manager();
+ const monitorsChangedHandlerId = monitorManager.connect('monitors-changed',
+ () => {
+ console.assert(display.get_n_monitors() === 1,
+ 'Expected a single monitor');
+ Scripting.scriptEvent('monitorsChanged');
+ monitorManager.disconnect(monitorsChangedHandlerId);
+ });
+ Shell.PerfLog.get_default().set_enabled(true);
+}
+
+/**
+ * run:
+ */
+export async function run() {
+ /* eslint-disable no-await-in-loop */
+ Scripting.defineScriptEvent('overviewShowDone', 'Overview finished showing');
+ Scripting.defineScriptEvent('overviewHideDone', 'Overview finished hiding');
+
+ Main.overview.connect('shown',
+ () => Scripting.scriptEvent('overviewShowDone'));
+ Main.overview.connect('hidden',
+ () => Scripting.scriptEvent('overviewHideDone'));
+
+ Main.overview.hide();
+ await Scripting.waitLeisure();
+
+ Main.overview.show();
+ await Scripting.waitLeisure();
+
+ /* eslint-enable no-await-in-loop */
+}
+
+let monitorsChanged = false;
+let overviewHidden = false;
+let overviewShown = false;
+
+/**
+ * script_monitorsChanged:
+ */
+export function script_monitorsChanged() {
+ monitorsChanged = true;
+}
+
+/**
+ * script_overviewHideDone:
+ */
+export function script_overviewHideDone() {
+ overviewHidden = true;
+}
+
+/**
+ * script_overviewShowDone:
+ */
+export function script_overviewShowDone() {
+ overviewShown = true;
+}
+
+/**
+ * finish:
+ */
+export function finish() {
+ if (!monitorsChanged)
+ throw new Error('Monitors never changed');
+
+ if (!overviewHidden)
+ throw new Error('Failed to hide overview');
+
+ if (!overviewShown)
+ throw new Error('Failed to show overview');
+}
--- /dev/null
+/* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^clutter"] }] */
+const Clutter = imports.gi.Clutter;
+const Gio = imports.gi.Gio;
+const Shell = imports.gi.Shell;
+const Main = imports.ui.main;
+const Scripting = imports.ui.scripting;
+
+export var METRICS = {
+ timeToDesktop: {
+ description: 'Time from starting graphical.target to desktop showing',
+ units: 'us',
+ },
+
+ overviewShowTime: {
+ description: 'Time to switch to overview view, first time',
+ units: 'us',
+ },
+
+ applicationsShowTime: {
+ description: 'Time to switch to applications view, first time',
+ units: 'us',
+ },
+
+ mainViewRedrawTime: {
+ description: 'Time to redraw the main view, full screen',
+ units: 'us',
+ },
+
+ overviewRedrawTime: {
+ description: 'Time to redraw the overview, full screen, 5 windows',
+ units: 'us',
+ },
+
+ applicationRedrawTime: {
+ description: 'Time to redraw frame with a maximized application update',
+ units: 'us',
+ },
+
+ geditStartTime: {
+ description: 'Time from gedit launch to window drawn',
+ units: 'us',
+ },
+};
+
+function waitAndDraw(milliseconds) {
+ let cb;
+
+ let timeline = new Clutter.Timeline({ duration: milliseconds });
+ timeline.start();
+
+ timeline.connect('new-frame', (_timeline, _frame) => {
+ global.stage.queue_redraw();
+ });
+
+ timeline.connect('completed', () => {
+ timeline.stop();
+ if (cb)
+ cb();
+ });
+
+ return callback => (cb = callback);
+}
+
+function waitSignal(object, signal) {
+ let cb;
+
+ let id = object.connect(signal, () => {
+ object.disconnect(id);
+ if (cb)
+ cb();
+ });
+
+ return callback => (cb = callback);
+}
+
+function extractBootTimestamp() {
+ const sp = Gio.Subprocess.new([
+ 'journalctl', '-b',
+ 'MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5',
+ 'UNIT=graphical.target',
+ '-o',
+ 'json',
+ ], Gio.SubprocessFlags.STDOUT_PIPE);
+ let result = null;
+
+ let datastream = Gio.DataInputStream.new(sp.get_stdout_pipe());
+ while (true) { // eslint-disable-line no-constant-condition
+ let [line, length_] = datastream.read_line_utf8(null);
+ if (line === null)
+ break;
+
+ let fields = JSON.parse(line);
+ result = Number(fields['__MONOTONIC_TIMESTAMP']);
+ }
+ datastream.close(null);
+ return result;
+}
+
+export async function run() {
+ /* eslint-disable no-await-in-loop */
+ Scripting.defineScriptEvent("desktopShown", "Finished initial animation");
+ Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview");
+ Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing");
+ Scripting.defineScriptEvent("applicationsShowStart", "Starting to switch to applications view");
+ Scripting.defineScriptEvent("applicationsShowDone", "Done switching to applications view");
+ Scripting.defineScriptEvent("mainViewDrawStart", "Drawing main view");
+ Scripting.defineScriptEvent("mainViewDrawDone", "Ending timing main view drawing");
+ Scripting.defineScriptEvent("overviewDrawStart", "Drawing overview");
+ Scripting.defineScriptEvent("overviewDrawDone", "Ending timing overview drawing");
+ Scripting.defineScriptEvent("redrawTestStart", "Drawing application window");
+ Scripting.defineScriptEvent("redrawTestDone", "Ending timing application window drawing");
+ Scripting.defineScriptEvent("collectTimings", "Accumulate frame timings from redraw tests");
+ Scripting.defineScriptEvent("geditLaunch", "gedit application launch");
+ Scripting.defineScriptEvent("geditFirstFrame", "first frame of gedit window drawn");
+
+ await Scripting.waitLeisure();
+ Scripting.scriptEvent('desktopShown');
+
+ let interfaceSettings = new Gio.Settings({
+ schema_id: 'org.gnome.desktop.interface',
+ });
+ interfaceSettings.set_boolean('enable-animations', false);
+
+ Scripting.scriptEvent('overviewShowStart');
+ Main.overview.show();
+ await Scripting.waitLeisure();
+ Scripting.scriptEvent('overviewShowDone');
+
+ await Scripting.sleep(1000);
+
+ Scripting.scriptEvent('applicationsShowStart');
+ // eslint-disable-next-line require-atomic-updates
+ Main.overview.dash.showAppsButton.checked = true;
+
+ await Scripting.waitLeisure();
+ Scripting.scriptEvent('applicationsShowDone');
+
+ await Scripting.sleep(1000);
+
+ Main.overview.hide();
+ await Scripting.waitLeisure();
+
+ // --------------------- //
+ // Tests of redraw speed //
+ // --------------------- //
+
+ global.frame_timestamps = true;
+ global.frame_finish_timestamp = true;
+
+ for (let k = 0; k < 5; k++)
+ await Scripting.createTestWindow({ maximized: true });
+ await Scripting.waitTestWindows();
+
+ await Scripting.sleep(1000);
+
+ Scripting.scriptEvent('mainViewDrawStart');
+ await waitAndDraw(1000);
+ Scripting.scriptEvent('mainViewDrawDone');
+
+ Main.overview.show();
+ Scripting.waitLeisure();
+
+ await Scripting.sleep(1500);
+
+ Scripting.scriptEvent('overviewDrawStart');
+ await waitAndDraw(1000);
+ Scripting.scriptEvent('overviewDrawDone');
+
+ await Scripting.destroyTestWindows();
+ Main.overview.hide();
+
+ await Scripting.createTestWindow({
+ maximized: true,
+ redraws: true,
+ });
+ await Scripting.waitTestWindows();
+
+ await Scripting.sleep(1000);
+
+ Scripting.scriptEvent('redrawTestStart');
+ await Scripting.sleep(1000);
+ Scripting.scriptEvent('redrawTestDone');
+
+ await Scripting.sleep(1000);
+ Scripting.scriptEvent('collectTimings');
+
+ await Scripting.destroyTestWindows();
+
+ global.frame_timestamps = false;
+ global.frame_finish_timestamp = false;
+
+ await Scripting.sleep(1000);
+
+ let appSys = Shell.AppSystem.get_default();
+ let app = appSys.lookup_app('org.gnome.gedit.desktop');
+
+ Scripting.scriptEvent('geditLaunch');
+ app.activate();
+
+ let windows = app.get_windows();
+ if (windows.length > 0)
+ throw new Error('gedit was already running');
+
+ while (windows.length == 0) {
+ await waitSignal(global.display, 'window-created');
+ windows = app.get_windows();
+ }
+
+ let actor = windows[0].get_compositor_private();
+ await waitSignal(actor, 'first-frame');
+ Scripting.scriptEvent('geditFirstFrame');
+
+ await Scripting.sleep(1000);
+
+ windows[0].delete(global.get_current_time());
+
+ await Scripting.sleep(1000);
+
+ interfaceSettings.set_boolean('enable-animations', true);
+ /* eslint-enable no-await-in-loop */
+}
+
+let overviewShowStart;
+let applicationsShowStart;
+let stagePaintStart;
+let redrawTiming;
+let redrawTimes = {};
+let geditLaunchTime;
+
+export function script_desktopShown(time) {
+ let bootTimestamp = extractBootTimestamp();
+ METRICS.timeToDesktop.value = time - bootTimestamp;
+}
+
+export function script_overviewShowStart(time) {
+ overviewShowStart = time;
+}
+
+export function script_overviewShowDone(time) {
+ METRICS.overviewShowTime.value = time - overviewShowStart;
+}
+
+export function script_applicationsShowStart(time) {
+ applicationsShowStart = time;
+}
+
+export function script_applicationsShowDone(time) {
+ METRICS.applicationsShowTime.value = time - applicationsShowStart;
+}
+
+export function script_mainViewDrawStart(_time) {
+ redrawTiming = 'mainView';
+}
+
+export function script_mainViewDrawDone(_time) {
+ redrawTiming = null;
+}
+
+export function script_overviewDrawStart(_time) {
+ redrawTiming = 'overview';
+}
+
+export function script_overviewDrawDone(_time) {
+ redrawTiming = null;
+}
+
+export function script_redrawTestStart(_time) {
+ redrawTiming = 'application';
+}
+
+export function script_redrawTestDone(_time) {
+ redrawTiming = null;
+}
+
+export function script_collectTimings(_time) {
+ for (let timing in redrawTimes) {
+ let times = redrawTimes[timing];
+ times.sort((a, b) => a - b);
+
+ let len = times.length;
+ let median;
+
+ if (len == 0)
+ median = -1;
+ else if (len % 2 == 1)
+ median = times[(len - 1) / 2];
+ else
+ median = Math.round((times[len / 2 - 1] + times[len / 2]) / 2);
+
+ METRICS[`${timing}RedrawTime`].value = median;
+ }
+}
+
+export function script_geditLaunch(time) {
+ geditLaunchTime = time;
+}
+
+export function script_geditFirstFrame(time) {
+ METRICS.geditStartTime.value = time - geditLaunchTime;
+}
+
+export function clutter_stagePaintStart(time) {
+ stagePaintStart = time;
+}
+
+export function clutter_paintCompletedTimestamp(time) {
+ if (redrawTiming != null && stagePaintStart != null) {
+ if (!(redrawTiming in redrawTimes))
+ redrawTimes[redrawTiming] = [];
+ redrawTimes[redrawTiming].push(time - stagePaintStart);
+ }
+ stagePaintStart = null;
+}